#include "FileScanner.h"
#include <algorithm>
#include <chrono>
#include <codecvt>
#include <locale>

FileScanner::FileScanner() 
    : shouldStop(false)
    , scanning(false)
    , currentStatus(ScanStatus::Idle)
    , totalFilesScanned(0)
    , totalBytesScanned(0)
    , activeThreads(0)
    , progressCallback(nullptr)
    , completeCallback(nullptr)
    , progressCallbackC(nullptr)
    , completeCallbackC(nullptr)
{
    initializeThreadPool();
}

FileScanner::~FileScanner() {
    stopScan();
    shutdownThreadPool();
}

bool FileScanner::startScan(const std::wstring& folderPath) {
    if (scanning.load()) {
        return false;
    }

    if (!isValidDirectory(folderPath)) {
        currentStatus = ScanStatus::Error;
        notifyComplete(ScanStatus::Error);
        return false;
    }

    // 重置状态
    shouldStop = false;
    scanning = true;
    currentStatus = ScanStatus::Scanning;
    totalFilesScanned = 0;
    totalBytesScanned = 0;

    // 清空之前的结果
    {
        std::lock_guard<std::mutex> lock(resultsMutex);
        scanResults.clear();
    }

    // 添加根目录扫描任务
    {
        std::lock_guard<std::mutex> lock(taskQueueMutex);
        taskQueue.push(ScanTask(folderPath, 0));
    }
    taskCondition.notify_all();

    return true;
}

void FileScanner::stopScan() {
    shouldStop = true;
    taskCondition.notify_all();
    
    if (scanning.load()) {
        scanning = false;
        currentStatus = ScanStatus::Cancelled;
        notifyComplete(ScanStatus::Cancelled);
    }
}

bool FileScanner::isScanning() const {
    return scanning.load();
}

ScanStatus FileScanner::getStatus() const {
    return currentStatus.load();
}

void FileScanner::setProgressCallback(ScanProgressCallback callback) {
    std::lock_guard<std::mutex> lock(callbackMutex);
    progressCallback = callback;
}

void FileScanner::setCompleteCallback(ScanCompleteCallback callback) {
    std::lock_guard<std::mutex> lock(callbackMutex);
    completeCallback = callback;
}

void FileScanner::setProgressCallbackC(ProgressCallbackC callback) {
    std::lock_guard<std::mutex> lock(callbackMutex);
    progressCallbackC = callback;
}

void FileScanner::setCompleteCallbackC(CompleteCallbackC callback) {
    std::lock_guard<std::mutex> lock(callbackMutex);
    completeCallbackC = callback;
}

uint64_t FileScanner::getTotalFilesScanned() const {
    return totalFilesScanned.load();
}

uint64_t FileScanner::getTotalBytesScanned() const {
    return totalBytesScanned.load();
}

void FileScanner::initializeThreadPool() {
    for (int i = 0; i < MAX_THREADS; ++i) {
        workerThreads.emplace_back(&FileScanner::workerThreadFunction, this);
    }
}

void FileScanner::shutdownThreadPool() {
    shouldStop = true;
    taskCondition.notify_all();
    
    for (auto& thread : workerThreads) {
        if (thread.joinable()) {
            thread.join();
        }
    }
    workerThreads.clear();
}

void FileScanner::workerThreadFunction() {
    while (!shouldStop.load()) {
        ScanTask task(L"");
        
        // 获取任务
        {
            std::unique_lock<std::mutex> lock(taskQueueMutex);
            taskCondition.wait(lock, [this] { 
                return !taskQueue.empty() || shouldStop.load(); 
            });
            
            if (shouldStop.load()) {
                break;
            }
            
            if (taskQueue.empty()) {
                continue;
            }
            
            task = taskQueue.front();
            taskQueue.pop();
        }
        
        // 执行扫描任务
        activeThreads++;
        scanDirectory(task.directoryPath, task.depth);
        activeThreads--;
        
        // 检查是否所有任务都完成
        if (activeThreads.load() == 0) {
            std::lock_guard<std::mutex> lock(taskQueueMutex);
            if (taskQueue.empty() && scanning.load()) {
                scanning = false;
                currentStatus = ScanStatus::Completed;
                notifyComplete(ScanStatus::Completed);
            }
        }
    }
}

void FileScanner::scanDirectory(const std::wstring& directoryPath, int depth) {
    if (shouldStop.load()) {
        return;
    }

#ifdef _WIN32
    scanDirectoryWin32(directoryPath, depth);
#else
    scanDirectoryPosix(directoryPath, depth);
#endif
}

#ifdef _WIN32
bool FileScanner::scanDirectoryWin32(const std::wstring& directoryPath, int depth) {
    WIN32_FIND_DATAW findData;
    std::wstring searchPath = directoryPath + L"\\*";
    HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findData);
    
    if (hFind == INVALID_HANDLE_VALUE) {
        return false;
    }
    
    do {
        if (shouldStop.load()) {
            break;
        }
        
        std::wstring fileName = findData.cFileName;
        if (fileName == L"." || fileName == L"..") {
            continue;
        }
        
        std::wstring fullPath = directoryPath + L"\\" + fileName;
        
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            // 子目录，添加到任务队列
            if (depth < 100) { // 防止无限递归
                std::lock_guard<std::mutex> lock(taskQueueMutex);
                taskQueue.push(ScanTask(fullPath, depth + 1));
                taskCondition.notify_one();
            }
        } else {
            // 文件，添加到结果
            uint64_t fileSize = combineFileSize(findData.nFileSizeHigh, findData.nFileSizeLow);
            FILETIME fileTime = getFileTime(findData);
            
            ScanResult result(fullPath, fileSize, fileTime);
            addScanResult(result);
            notifyProgress(fullPath, fileSize);
            
            totalFilesScanned++;
            totalBytesScanned += fileSize;
        }
        
    } while (FindNextFileW(hFind, &findData) && !shouldStop.load());
    
    FindClose(hFind);
    return true;
}

FILETIME FileScanner::getFileTime(const WIN32_FIND_DATAW& findData) {
    return findData.ftLastWriteTime;
}
#else
bool FileScanner::scanDirectoryPosix(const std::wstring& directoryPath, int depth) {
    std::string dirPath = wstringToString(directoryPath);
    DIR* dir = opendir(dirPath.c_str());
    
    if (!dir) {
        return false;
    }
    
    struct dirent* entry;
    while ((entry = readdir(dir)) != nullptr && !shouldStop.load()) {
        std::string fileName = entry->d_name;
        if (fileName == "." || fileName == "..") {
            continue;
        }
        
        std::string fullPath = dirPath + "/" + fileName;
        std::wstring wFullPath = stringToWString(fullPath);
        
        struct stat fileStat;
        if (stat(fullPath.c_str(), &fileStat) == 0) {
            if (S_ISDIR(fileStat.st_mode)) {
                // 子目录
                if (depth < 100) {
                    std::lock_guard<std::mutex> lock(taskQueueMutex);
                    taskQueue.push(ScanTask(wFullPath, depth + 1));
                    taskCondition.notify_one();
                }
            } else if (S_ISREG(fileStat.st_mode)) {
                // 普通文件
                uint64_t fileSize = static_cast<uint64_t>(fileStat.st_size);
                FILETIME fileTime = getFileTime(fileStat);
                
                ScanResult result(wFullPath, fileSize, fileTime);
                addScanResult(result);
                notifyProgress(wFullPath, fileSize);
                
                totalFilesScanned++;
                totalBytesScanned += fileSize;
            }
        }
    }
    
    closedir(dir);
    return true;
}

FILETIME FileScanner::getFileTime(const struct stat& fileStat) {
    FILETIME ft;
    // 简化实现，实际应该转换Unix时间戳到Windows FILETIME
    ft.dwLowDateTime = static_cast<uint32_t>(fileStat.st_mtime);
    ft.dwHighDateTime = 0;
    return ft;
}
#endif

void FileScanner::addScanResult(const ScanResult& result) {
    std::lock_guard<std::mutex> lock(resultsMutex);
    scanResults.push_back(result);
}

void FileScanner::notifyProgress(const std::wstring& filePath, uint64_t fileSize) {
    std::lock_guard<std::mutex> lock(callbackMutex);
    
    uint64_t totalFiles = totalFilesScanned.load();
    
    if (progressCallback) {
        progressCallback(filePath, fileSize, totalFiles);
    }
    
    if (progressCallbackC) {
        progressCallbackC(filePath.c_str(), fileSize, totalFiles);
    }
}

void FileScanner::notifyComplete(ScanStatus status) {
    std::lock_guard<std::mutex> lock(callbackMutex);
    
    if (completeCallback) {
        std::lock_guard<std::mutex> resultsLock(resultsMutex);
        completeCallback(scanResults, status);
    }
    
    if (completeCallbackC) {
        std::lock_guard<std::mutex> resultsLock(resultsMutex);
        completeCallbackC(scanResults.data(), static_cast<int>(scanResults.size()), 
                         static_cast<int>(status));
    }
}

std::wstring FileScanner::stringToWString(const std::string& str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    return converter.from_bytes(str);
}

std::string FileScanner::wstringToString(const std::wstring& wstr) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    return converter.to_bytes(wstr);
}

bool FileScanner::isValidDirectory(const std::wstring& path) {
#ifdef _WIN32
    DWORD attributes = GetFileAttributesW(path.c_str());
    return (attributes != INVALID_FILE_ATTRIBUTES) && 
           (attributes & FILE_ATTRIBUTE_DIRECTORY);
#else
    std::string dirPath = wstringToString(path);
    struct stat statBuf;
    return (stat(dirPath.c_str(), &statBuf) == 0) && S_ISDIR(statBuf.st_mode);
#endif
}

uint64_t FileScanner::combineFileSize(uint32_t high, uint32_t low) {
    return (static_cast<uint64_t>(high) << 32) | low;
}